added samples
[windows-sources.git] / sdk / samples / all in on code / Visual Studio 2008 / VBSL3SocketServer / SocketClient.vb
bloba2b72553078e60b5d7a358a70011314558e56481
1 '****************************** Module Header ******************************'
2 ' Module Name: SocketClient.vb
3 ' Project: VBSL3SocketServer
4 ' Copyright (c) Microsoft Corporation.
5 '
6 ' Socket Server application code file, can serve Silverlight and normal socket
7 ' Client.
8 '
9 ' This source is subject to the Microsoft Public License.
10 ' See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
11 ' All other rights reserved.
13 ' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
14 ' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
15 ' WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
16 '***************************************************************************'
17 Imports System
18 Imports System.Collections.Generic
19 Imports System.Linq
20 Imports System.Text
21 Imports System.Net.Sockets
22 Imports System.Net
24 Namespace VBSL3SocketServer
25 Public Class SocketMessageEventArgs
26 Inherits EventArgs
27 Private _Error As Exception
28 Public Property [Error]() As Exception
29 Get
30 Return _Error
31 End Get
32 Set(ByVal value As Exception)
33 _Error = value
34 End Set
35 End Property
36 Private _Data As String
37 Public Property Data() As String
38 Get
39 Return _Data
40 End Get
41 Set(ByVal value As String)
42 _Data = value
43 End Set
44 End Property
45 End Class
47 Public Class SocketClient
48 ' Define 3 events for async operation:
49 ' Open,Receive and Send
50 Public Event MessageReceived As EventHandler(Of SocketMessageEventArgs)
51 Public Event MessageSended As EventHandler(Of SocketMessageEventArgs)
52 Public Event ClientConnected As EventHandler(Of SocketMessageEventArgs)
54 ' Set receive buffer size
55 Shared ReadOnly BUFFER_SIZE As Integer = 65536
57 ' Define the End-of-message char, which is used for separating
58 ' byte array into string messages
59 Shared ReadOnly EOM_MARKER As Char = ChrW(127)
61 ' The encapsulated socket
62 Private _InnerSocket As Socket
63 Public Property InnerSocket() As Socket
64 Get
65 Return _InnerSocket
66 End Get
67 Private Set(ByVal value As Socket)
68 _InnerSocket = value
69 End Set
70 End Property
73 Public Sub New(ByVal socket As Socket)
74 If socket Is Nothing Then
75 Throw New Exception("Socket cannot be null")
76 End If
77 InnerSocket = socket
79 ' Initialize string decoder
80 encoding = New UTF8Encoding(False, True)
81 End Sub
82 Public Sub New(ByVal addfamily As AddressFamily, ByVal socktype As SocketType, ByVal protype As ProtocolType)
83 InnerSocket = New Socket(addfamily, socktype, protype)
84 encoding = New UTF8Encoding(False, True)
85 End Sub
87 #Region "Socket async connect"
89 ' Get socket connect status
90 Public ReadOnly Property Connected() As Boolean
91 Get
92 Return InnerSocket.Connected
93 End Get
94 End Property
96 ' Close socket
97 Public Sub Close()
98 InnerSocket.Close()
99 End Sub
101 ''' <summary>
102 ''' Connect socket to endpoint asynchronously.
103 ''' Possible exception:
104 ''' ArgumentException
105 ''' ArgumentNullException
106 ''' InvalidOperationException
107 ''' SocketException
108 ''' NotSupportedException
109 ''' ObjectDisposedException
110 ''' SecurityException
111 ''' Details at: http://msdn.microsoft.com/en-us/library/bb538102.aspx
112 ''' </summary>
113 ''' <param name="ep">remote endpoint</param>
114 Public Sub ConnectAsync(ByVal ep As EndPoint)
115 If InnerSocket.Connected Then
116 Exit Sub
117 End If
119 ' Initialize socketAsyncEventArgs
120 ' Set remote connect endpoint
121 Dim connectEventArgs = New SocketAsyncEventArgs()
122 connectEventArgs.RemoteEndPoint = ep
123 AddHandler connectEventArgs.Completed, AddressOf connectEventArgs_Completed
125 ' Call ConnectAsync method, if method returned false
126 ' it means the result has returned synchronously
127 If Not InnerSocket.ConnectAsync(connectEventArgs) Then
128 ' Call method to handle connect result
129 ProcessConnect(connectEventArgs)
130 End If
131 End Sub
133 ' When connectAsync completed, call method to handle connect result
134 Private Sub connectEventArgs_Completed(ByVal sender As Object, ByVal e As SocketAsyncEventArgs)
135 ProcessConnect(e)
136 End Sub
138 ' Invoke ClientConnected event to return result
139 Private Sub ProcessConnect(ByVal e As SocketAsyncEventArgs)
140 If e.SocketError = SocketError.Success Then
141 OnClientConnected(Nothing)
142 Else
143 OnClientConnected(New SocketException(CInt(e.SocketError)))
144 End If
145 End Sub
147 Private Sub OnClientConnected(ByVal [error] As Exception)
148 Dim sockargs As New SocketMessageEventArgs()
149 sockargs.Error = [error]
150 RaiseEvent ClientConnected(Me, sockargs)
151 End Sub
152 #End Region
154 #Region "Socket async Send"
156 ''' <summary>
157 ''' Use Socket to send string message.
158 ''' Possible exception:
159 ''' FormatException
160 ''' ArgumentException
161 ''' InvalidOperationException
162 ''' NotSupportedException
163 ''' ObjectDisposedException
164 ''' SocketException
165 ''' </summary>
166 ''' <param name="data">message to be sent</param>
167 Public Sub SendAsync(ByVal data As String)
169 ' If message data contains EOM_MARKER char,
170 ' throw exception
171 If data.Contains(EOM_MARKER) Then
172 Throw New Exception("Unallowed chars existed in message")
173 End If
175 ' Add End-of-message char at message end.
176 data += EOM_MARKER
178 ' Get UTF8 encoded byte array
179 Dim bytesdata = encoding.GetBytes(data)
181 ' Initialize SendEventArgs
182 Dim sendEventArgs = New SocketAsyncEventArgs()
183 sendEventArgs.SetBuffer(bytesdata, 0, bytesdata.Length)
184 AddHandler sendEventArgs.Completed, AddressOf sendEventArgs_Completed
186 ' Call SendAsync method, if method returned false
187 ' it means the result has returned synchronously
188 If Not InnerSocket.SendAsync(sendEventArgs) Then
189 ProcessSend(sendEventArgs)
190 End If
191 End Sub
193 ' When sendAsync completed, call method to handle send result
194 Private Sub sendEventArgs_Completed(ByVal sender As Object, ByVal e As SocketAsyncEventArgs)
195 ProcessSend(e)
196 End Sub
198 ' Invoke MessageSended event to return result
199 Private Sub ProcessSend(ByVal e As SocketAsyncEventArgs)
200 If e.SocketError = SocketError.Success Then
201 OnMessageSended(Nothing)
202 Else
203 OnMessageSended(New SocketException(CInt(e.SocketError)))
204 End If
205 End Sub
207 Private Sub OnMessageSended(ByVal [error] As Exception)
208 Dim sockargs As New SocketMessageEventArgs()
209 sockargs.Error = [error]
210 RaiseEvent MessageSended(Me, sockargs)
211 End Sub
212 #End Region
214 #Region "Socket async Receive"
216 ' Define flag to indicate receive status
217 Private _isReceiving As Boolean
219 ''' <summary>
220 ''' Start receiving bytes from socket and invoke
221 ''' MessageReceived event when each message received.
222 ''' Possible exception:
223 ''' ArgumentException
224 ''' InvalidOperationException
225 ''' NotSupportedException
226 ''' ObjectDisposedException
227 ''' SocketException
228 ''' Details at http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.receiveasync.aspx
229 ''' </summary>
230 Public Sub StartReceiving()
232 ' Check if socket is started receiving already
233 If Not _isReceiving Then
234 _isReceiving = True
235 Else
236 Exit Sub
237 End If
240 ' Initialize receiving buffer
241 Dim buffer = New Byte(BUFFER_SIZE) {}
243 ' Initialize receive event args
244 Dim receiveEventArgs = New SocketAsyncEventArgs()
245 receiveEventArgs.SetBuffer(buffer, 0, BUFFER_SIZE)
246 AddHandler receiveEventArgs.Completed, AddressOf receiveEventArgs_Completed
248 ' Call ReceiveAsync method, if method returned false
249 ' it means the result has returned synchronously
250 If Not InnerSocket.ReceiveAsync(receiveEventArgs) Then
251 ProcessReceive(receiveEventArgs)
252 End If
253 Catch ex As Exception
254 StopReceiving()
255 Throw ex
256 End Try
257 End Sub
259 ' Stop receiving bytes from socket
260 Public Sub StopReceiving()
261 _isReceiving = False
262 End Sub
264 Private Sub receiveEventArgs_Completed(ByVal sender As Object, ByVal e As SocketAsyncEventArgs)
265 ProcessReceive(e)
266 End Sub
268 ' Process receiveAsync complete event
269 Private receivemessage As String = ""
270 Private encoding As Encoding
271 Private taillength As Integer
272 Private Sub ProcessReceive(ByVal e As SocketAsyncEventArgs)
273 ' When got Error, invoke MessageReceived event
274 ' to pass the error info to user
275 If e.SocketError <> SocketError.Success Then
276 StopReceiving()
277 OnMessageReceived(Nothing, New SocketException(CInt(e.SocketError)))
278 Exit Sub
279 End If
282 '#Region "String Decoding"
283 ' Decoding bytes to string.
284 ' Note that UTF-8 is variable-length encode, we need check the byte
285 ' array tail in case of separating one character into two.
286 Dim receivestr As String = ""
287 ' Try decode string
289 receivestr = encoding.GetString(e.Buffer, 0, taillength + e.BytesTransferred)
290 ' If decode successful, reset tail length
291 taillength = 0
292 Catch ex As DecoderFallbackException
293 ' If got decode exception, remove the array tail and re decode
295 receivestr = encoding.GetString(e.Buffer, 0, taillength + e.BytesTransferred - ex.BytesUnknown.Length)
296 ' reset tail length
297 taillength = ex.BytesUnknown.Length
298 ex.BytesUnknown.CopyTo(e.Buffer, 0)
299 Catch ex2 As DecoderFallbackException
300 ' If still got decode exception, stop receiving.
301 Throw New Exception("Message decode failed.", ex2)
303 '#End Region
304 End Try
305 End Try
306 ' Check if message ended
307 Dim eompos As Integer = receivestr.IndexOf(EOM_MARKER)
308 While eompos <> -1
309 ' Compose a complete message
310 receivemessage += receivestr.Substring(0, eompos)
312 ' Notify message received
313 OnMessageReceived(receivemessage, Nothing)
315 ' Get the remaining string
316 receivemessage = ""
317 receivestr = receivestr.Substring(eompos + 1, receivestr.Length - eompos - 1)
319 ' Check if it still has EOM in string
320 eompos = receivestr.IndexOf(EOM_MARKER)
321 End While
322 receivemessage += receivestr
324 ' Stop receiving.
325 If Not _isReceiving Then
326 Exit Sub
327 End If
329 ' Reset buffer offset
330 e.SetBuffer(taillength, BUFFER_SIZE - taillength)
332 ' Keep receiving
333 If Not InnerSocket.ReceiveAsync(e) Then
334 ProcessReceive(e)
335 End If
336 Catch ex As Exception
337 ' Return error through MessageReceived event
338 OnMessageReceived(Nothing, ex)
339 StopReceiving()
340 End Try
341 End Sub
343 Private Sub OnMessageReceived(ByVal data As String, ByVal [error] As Exception)
344 Dim sockargs As New SocketMessageEventArgs()
345 sockargs.Data = data
346 sockargs.Error = [error]
347 RaiseEvent MessageReceived(Me, sockargs)
348 End Sub
349 #End Region
350 End Class
351 End Namespace